package org.luxor.commons.schedule.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.luxor.commons.core.utils.StringUtils;
import org.luxor.commons.schedule.constant.ScheduleLogStatus;
import org.luxor.commons.schedule.entity.ScheduleJobLogEntity;
import org.luxor.commons.schedule.service.IScheduleJobLogService;
import org.luxor.commons.schedule.service.IScheduleJobService;
import org.luxor.commons.schedule.utils.ReflectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.util.Assert;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Scheduled切面处理类
 *
 * @author admin
 * @date 2020-02-28 19:17
 */
@Aspect
@Order()
public class ScheduledAspect implements ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(ScheduledAspect.class);

    private ApplicationContext applicationContext;

    private IScheduleJobService scheduleJobService;

    private IScheduleJobLogService scheduleJobLogService;

    public ScheduledAspect(IScheduleJobService scheduleJobService, IScheduleJobLogService scheduleJobLogService) {
        logger.debug("Initialize ScheduledAspect ...");

        Assert.notNull(scheduleJobService, "scheduleJobService must be specified");
        this.scheduleJobService = scheduleJobService;

        Assert.notNull(scheduleJobLogService, "scheduleJobLogService must be specified");
        this.scheduleJobLogService = scheduleJobLogService;

        logger.info("Initialize ScheduledAspect Success,bye");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 定义缓存逻辑
     */
    @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)||@annotation(org.springframework.scheduling.annotation.Schedules)")
    public Object scheduled(ProceedingJoinPoint pjp) throws Throwable {
        String beanName = null;
        Map<String, Object> beanMap = (LinkedHashMap) applicationContext.getBeansOfType(pjp.getTarget().getClass());
        for (String name : beanMap.keySet()) {
                beanName = name;
        }
        Method method = ReflectUtil.getMethod(pjp);
        //数据库保存执行记录
        ScheduleJobLogEntity scheduleJob = new ScheduleJobLogEntity();
        Long jobId = scheduleJobService.getLogId(beanName, method.getName());
        scheduleJob.setJobId(jobId);
        scheduleJob.setBeanName(beanName);
        scheduleJob.setMethodName(method.getName());
        scheduleJob.setCreateTime(new Date());

        //任务开始时间
        long startTime = System.currentTimeMillis();

        Object obj;
        try {
            //执行任务
            if (logger.isDebugEnabled()) {
                logger.debug("任务准备执行，任务ID：" + scheduleJob.getJobId());
            }

            obj = pjp.proceed();

            //任务执行总时长
            long times = System.currentTimeMillis() - startTime;
            scheduleJob.setTimes(times);
            //任务状态    0：成功    1：失败
            scheduleJob.setStatus(ScheduleLogStatus.SUCCEED.getValue());

            if (logger.isDebugEnabled()) {
                logger.debug("任务执行完毕，任务ID：" + scheduleJob.getJobId() + "  总共耗时：" + times + "毫秒");
            }
            return obj;
        } catch (Throwable e) {
            logger.error("任务执行失败，任务ID：" + scheduleJob.getJobId(), e);
            //任务执行总时长
            long times = System.currentTimeMillis() - startTime;
            scheduleJob.setTimes(times);
            //任务状态    0：成功    1：失败
            scheduleJob.setStatus(ScheduleLogStatus.FAILURE.getValue());
            scheduleJob.setError(StringUtils.substring(e.toString(), 0, 2000));
            throw e;
        } finally {
            if (scheduleJobLogService != null) {
                scheduleJobLogService.saveLog(scheduleJob);
            }
        }
    }

}